/*****************************************************************************************/
/* ECSE 426 - Microprocessor - Fall 2009
/* Lab Experiment 3 - Logic of the program
/* MAIN.C
/* @author: Danny Wu - 260238209 - B.Comp.Eng
/* @author: Han-Sheng Chin - 260209715 - B.Elec.Eng
/* @version: 09.10.23.1508 
/****************************************************************************************/

#include <msp430x14x.h>
#include "main.h"
#include "FreeRTOS.h"
#include "task.h"
//#include "constants.h"
//#include "uart.h"
//#include "reliableTransfer.h"
#include "semphr.h" // semaphores
#include "serial.h"
#include "game.h"

#define mainSTACK_SIZE				configMINIMAL_STACK_SIZE
#define mainFSM_PRIORITY			( tskIDLE_PRIORITY + 1 )
#define gameFSM_PRIORITY			( tskIDLE_PRIORITY + 1 )
#define Rx_PRIORITY                             ( tskIDLE_PRIORITY + 2 )
#define Tx_PRIORITY                             ( tskIDLE_PRIORITY + 1 )

int state;    // Global variable for state of the finite state machine.
int func;     // Global variable for determining which option to use in input interrupt.
int exit=0;     // Global variable for determining whether to exit program or not.
int input;    // Global variable to store the input values from the keyboard.
int waitInput;  // Global variable to determine if the FSM is waiting for input.
int regAdd;     // Global variable for the register address to be modified.
int regVal;     // Global variable for the new register value.
char msg[64];     // message to be transmitted
char gameSecretNum[4];
int msgCtr;     //counter for msg length
int guessCount=0;

char name[24];

xSemaphoreHandle xKeySemaphore = NULL;
xSemaphoreHandle xPrintSemaphore = NULL;
xSemaphoreHandle xFSMSemaphore = NULL;
xSemaphoreHandle xStartSemaphore = NULL;
xSemaphoreHandle xReplySemaphore = NULL;  // for synchronisation
xSemaphoreHandle xEndGameSemaphore = NULL;  // for synchronisation
xSemaphoreHandle xRx1Semaphore;

static xTaskHandle mainFSM = NULL;

PACKET lastReceived;

static portTASK_FUNCTION_PROTO( vStartFsm, pvParameters );
//static portTASK_FUNCTION_PROTO( vEndGame, pvParameters );

int cc2500add[14] = {0x30, 0x31, 0x32, 0x33,0x34, 0x35, 0x36, 0x37,0x38, 0x39, 0x3A, 0x3B,0x3C,0x3D};
char *cc2500name[14] = {"PARTNUM  ", "VERSION  ", "FREQEST  ", "LQI     ",
                      "RSSI    ", "MARCSTATE", "WORTIME1", "WORTIME0", "PKSTATUS", "VCO_VC_DAC",
                      "TXBYTES ", "RXBYTES  ", "RCCTRL1_STATUS", "RCCTRL0_STATUS"};
char *cc2500configReg[0x2F] = {"IOCFG2","IOCFG1","IOCFG0","FIFOTHR","SYNC1","SYNC0","PKTLEN","PKTCTRL1","PKTCTRL0","ADDR","CHANNR","FSCTRL1","FSCTRL0","FREQ2","FREQ1","FREQ0",
"MDMCFG4","MDMCFG3","MDMCFG2","MDMCFG1","MDMCFG0","DEVIATN","MCSM2","MCSM1","MCSM0","FOCCFG","BSCFG","AGCTRL2","AGCTRL1","AGCTRL0","WOREVT1","WOREVT0",
"WORCTRL","FREND1","FREND0","FSCAL3","FSCAL2","FSCAL1","FSCAL0","RCCTRL1","RCCTRL0","FSTEST","PTEST","AGCTEST","TEST2","TEST1","TEST0"};

//TI variables
char txBuffer[64];
char rxBuffer[64];

//FSM variables
int inputCount = 0;
char inputOne, inputTwo;


/**
 * Main function
 * Used to run the logic of our program
 * -Set screenCap variable to 1 if we want to capture values from Logic Analyzer
 * *Initialize configuration of the clock
 * *Enable interrupts
 */
void main(void){  
  char x;
  int i=0;
  char heya[20];
  int screenCap = 0; //capturing logic analyzer signals mode
  gameSecretNum[0] = '1';
  gameSecretNum[1] = '5';
  gameSecretNum[2] = '6';
  gameSecretNum[3] = '4';

  heya[0] = 'B';
  heya[1] = 'R';
  heya[2] = 'A';
  heya[3] = 'D';
  heya[4] = '!';
  heya[5] = '\0';

  //initialize configuration of the clock
  WDTCTL = WDTPW + WDTHOLD;             // Stop WDT
  BCSCTL1 &= ~XT2OFF;                   // XT2OFF
  BCSCTL2 |= SELS;                      // MCLK = SMCLK = XT2 (safe)
  _EINT();                              // Enable interrupts
  //start configuration
  initRsUART();
  TI_CC_SPISetup(); //calling TI code or initSpiUART(); TI_CC_SPISetup()
  ccResetChip();  
  clearScreen(); 
  ccConfigBeacon();
   
  //store and reload value from flash
  //clearAllFlash();
  //saveToFlash();
  //loadFromFlash();
  initPacket(0xFF, 0xff, heya);
  initLCD();
  
  
 
  // create semaphores
  vSemaphoreCreateBinary( xKeySemaphore );
  //vSemaphoreCreateBinary( xReplySemaphore );
  //vSemaphoreCreateBinary( xEndGameSemaphore );
  //vSemaphoreCreateBinary( xRx1Semaphore );
  vSemaphoreCreateBinary( xStartSemaphore );
  //xPrintSemaphore = xSemaphoreCreateMutex();

 /* while(exit != 1){
  
    switch(state){

      case 0:     // Ready mode. Print menu and wait for user input.
        printMenu();
        func = 0;
        state = 8;  // Wait
        break;

      case 1:     // Dump registers mode. Print the data of all the registers.
        dumpConfigReg();
        println(""); 
        dumpStatusReg();
        println("Press ENTER for menu or ESC to exit program.");
        func = 1;
        state = 8;  // Wait
        break;

      case 2:     // Modify register mode. Print the data of the old value and wait for user input on new value.
        modReg();
        println("Press ENTER for menu or ESC to exit program.");
        func = 1;
        state = 8;  // Wait
        break;

      case 5:
        println("Game mode!");
        //startGame();
        xCreateGameTask( gameFSM_PRIORITY );
        
        exit = 1;
        break;      
      
      case 6:     // reset program.
        
        state=0;
        break;

      case 8:     // Wait for input
        if(xSemaphoreTake( xKeySemaphore, portMAX_DELAY )){ // block for 2 seconds to save processr time
          //ccCommandStrobe(SIDLE);
        }
        //vTaskDelay(xTimeToWait);
        break;
    }//end switch  
  }// end of while loop*/
  
  //start tasks and FSM
  ccCommandStrobe(SRX);//
  xSerialPortInitCustom( (unsigned portBASE_TYPE) 30 );
  xCreateGameTask( gameFSM_PRIORITY );
  vStartHeartTasks( Rx_PRIORITY, (unsigned portBASE_TYPE) 1 );
  vStartGuessTasks( Tx_PRIORITY );
  vStartPreGame( Rx_PRIORITY );
  

  // create fsm task
  //xTaskCreate( vStartFsm, ( signed char * ) "MenuFsm", mainSTACK_SIZE, mainFSM, mainFSM_PRIORITY, NULL );
  //xTaskCreate( vEndGame, ( signed char * ) "EndGame", mainSTACK_SIZE, NULL, END_GAME_PRIORITY, NULL );
  
  // Start the scheduler
  vTaskStartScheduler();

  //leave program
  println("Shouldn't Be Here...");
  //while(TRUE);

}//end main

/*void vResumeMain( void ){
  vTaskResume(mainFSM);
}*/

/**
 * This function is only used to print the menu interface.
 *
 */
void printMenu(void) {
  clearScreen();
  println("*******************************************************************");
  println("Welcome to Danny & Han's CC2500 Wireless Transceiver Interface");
  println("*******************************************************************");
  println("1. Dump all registers.");
  println("2. Modify content of a register.");
  println("3. Send and receive data packets.");
  println("4. Receive data packets only.");
  println("5. Game mode.");
  println("Select an option:  ");
} //end printMenu

/**
 *  This function dumps all the configuration registers
 */
void dumpConfigReg(void) {
  char i;
  int ctr = 0;
  /*char *cc2500configReg[0x2F] = {"IOCFG2","IOCFG1","IOCFG0","FIFOTHR","SYNC1","SYNC0","PKTLEN","PKTCTRL1","PKTCTRL0","ADDR","CHANNR","FSCTRL1","FSCTRL0","FREQ2","FREQ1","FREQ0",
                   "MDMCFG4","MDMCFG3","MDMCFG2","MDMCFG1","MDMCFG0","DEVIATN","MCSM2","MCSM1","MCSM0","FOCCFG","BSCFG","AGCTRL2","AGCTRL1","AGCTRL0","WOREVT1","WOREVT0",
                   "WORCTRL","FREND1","FREND0","FSCAL3","FSCAL2","FSCAL1","FSCAL0","RCCTRL1","RCCTRL0","FSTEST","PTEST","AGCTEST","TEST2","TEST1","TEST0"};
  */println("*****************************************");
  println("Start dumping configuration registers");
  println("*****************************************");
  println("\nADDRESS\t\tREG NAME\t\tVALUE\n");
  for(i=0x00; i < 0x2F;i++){ 
    println("");
    printHex(i);
    print("\t\t");
    print(cc2500configReg[ctr++]);
    print("    \t\t");
    printHex(spiReadReg(i));
  }//end for
  println("*****************************************");
  println("End dumping configuration registers");
  println("*****************************************");
}//end dumpConfigReg

/**
 *  This function dumps all the status registers
 */
void dumpStatusReg(void) {
  char i;
  int ctr = 0;
  /*char *regName[14] = {"PARTNUM  ", "VERSION  ", "FREQEST  ", "LQI     ",
                      "RSSI    ", "MARCSTATE", "WORTIME1", "WORTIME0", "PKSTATUS", "VCO_VC_DAC",
                      "TXBYTES ", "RXBYTES  ", "RCCTRL1_STATUS", "RCCTRL0_STATUS"};
  */println("*****************************************");
  println("Start dumping status registers");
  println("*****************************************");
  println("\nADDRESS\t\tREG NAME\t\tVALUE\n");
  for(i=0x30; i < 0x3E;i++){ 
    println("");
    printHex(i);
    print("\t\t");
    print(cc2500name[ctr++]);
    print("\t\t");
    printHex(spiReadReg(i));
  }//end for
  println("*****************************************");
  println("End dumping status registers");
  println("*****************************************");
}//end dumpConfigReg


void modReg(void) {
  char x;
  println("************************************************");
  println("2. Modify content of a register");
  println("************************************************");
  println("Choose desired register to be modified: 0x");
  func = 2;
  waitInput = 1;
  while (waitInput);                // Wait for input
  if (func == 2)
  {
    x = spiReadReg(regAdd);
//    if(x < 0x2F){
      println("Register name is ");   // Still have to figure out how to print register name.
      print(cc2500configReg[regAdd]);
      println(" Old value = ");                    // Still have to figure out how to print old value.
      printHex(x);
      println(" New value = 0x");
      func = 3;
      waitInput = 1;
      while (waitInput);                // Wait for input
//    }else{
//      println("Configuration address is out of bound!\n");
//    }//end if 
  } // end if
} //end modReg

/**
 * This function is used to send and receive
 *
 *
 */
void sendReceive(void) {        // Function to send and receive message.
  char tmp;
  char gu[4];
  gu[0] = '1';
  gu[1] = '2';
  gu[2] = '3';
  gu[3] = '4';

  msgCtr = 0;
  println("************************************************");
  println("3. Send and receive data packets");
  println("************************************************");
  println("---Press [ENTER] to send---"); 
  println("Enter the message to send: ");
  func = 5;
  waitInput = 1;
  while(waitInput);
  //send message
  if(func == 5){
    println("before the TRaNSFER~~~");
    xSendGuess(gu);//ccTX(msg);// TESTING
   
    //wait until its idle
    /*while(!((tmp = TI_CC_SPIReadStatus(MARCSTATE)) == 0x01)) {
      printHex(tmp);
      printHex(TI_CC_SPIReadStatus(TXBYTES));
    }*/
//    //receive mode
//    ccCommandStrobe(SFRX);
//    ccCommandStrobe(SRX);
  }//end if
} //end sendReceive

void receiveOnly(void) {
  println("************************************************");
  println("4. Receive data packets only");
  println("************************************************");

  //receive mode
  //xSemaphoreGive(xRx1Semaphore);
  ccCommandStrobe(SRX);
  //ccRX();  // Code to receive data only.
} //end receiveOnly

//logic of the final state machine
void logicFSM (char val){
  switch (func) {
      case 0: // main menu
        switch(val) {
          case 0x31: // key '1': dump all registers
            putChar('\b');
            putChar(val);
            input = 1;
            break;
          case 0x32: // key '2': modify a register
            putChar('\b');
            putChar(val);
            input = 2;
            break;
          case 0x33: // key '3': send and receive
            putChar('\b');
            putChar(val);
            input = 3;
            break;
          case 0x34: // key '4': receive only
            putChar('\b');
            putChar(val);
            input = 4;
            break;
          case 0x35: // key '5': game mode
            putChar('\b');
            putChar(val);
            input = 5;
            break;
          case 0x1b: // escape key exits program
            exit = 1;
            break;
          case 0x0d: // enter key
            state = input;
            input = 0;
            break;
          case 0x08: //backspace
            putChar('\b');
            putChar(0x20);
            //putChar('\b');       
            break;
          default:
  //          println(" In*valid input! ");
  //          putChar(val);
  //          println("Select an option:  ");
            break;
        } // end nested switch of case func=0
        break;
      case 1:                                                  // Option to print menu or exit at the end of each function.
        switch(val) {
          case 0x0d: // enter key
            state = 0;
            break;
          case 0x1b: // escape key
            exit = 1;
            break;
          default:
            break;
        } // end nested switch of case func=1
        break;
      case 2:                                                // Modify register mode - input register address
        switch(val) {
          case 0x1b: // excape key
            println("Operation aborted!");
            state = 0;
            func = 0;
            waitInput = 0;
            break;
          case 0x0d: // enter key
            if (inputCount == 2)
            {
  
              regAdd = combineInput(inputOne, inputTwo);        // Combine the two inputs into one. Function not written yet.
              println("Register address is: ");
              printHex(regAdd); //debug
  
              inputCount = 0;
              waitInput = 0;
            }
            else
            {
              println("Invalid input! Press escape to return to menu!");
            }
            break;
          default:
            // Store the value of the register address.
            if (inputCount == 0)
            {
              inputOne = val;
              putChar(inputOne);
              inputCount++;
            }
            else if (inputCount == 1)
            {
              inputTwo = val;
              putChar(inputTwo);
              inputCount++;
            }
            break;
        } // end nested switch of case func=2
        break;
      case 3:                                                // Modify register mode - input register value
        switch(val) {
          case 0x1b: // excape key
            println("Operation aborted!");
            state = 0;
            func = 0;
            waitInput = 0;
            break;
          case 0x0d: // enter key
            if (inputCount == 2)
            {
  
              regVal = combineInput(inputOne, inputTwo);        // Combine the two inputs into one. Function not written yet.
              println("New register value is ");
  
              printHex(regVal); //debug
              inputCount = 0;
              waitInput = 0;
              spiWriteReg(regAdd, regVal);
              println("Register changed!");
            }
            else
            {
              println("Invalid input! Press escape to return to menu!");
            }
            break;
          default:
            // Store the new value of the register.
            if (inputCount == 0)
            {
              inputOne = val;
              putChar(inputOne);
              inputCount++;
            }
            else if (inputCount == 1)
            {
              inputTwo = val;
              putChar(inputTwo);
              inputCount++;
            }
            break;
        } // end nested switch of case func=3
        break;
  
        case 5:
          switch(val) {
            case 0x08: //backspace
              putChar('\b');
              putChar(0x20);
              putChar('\b');  
              msgCtr--;
              msg[msgCtr] = '\0';           
              break;
            case 0x0d: // enter key
              waitInput = 0;
              break;
            case 0x1b: // escape key
              println("Operation aborted!");
              state = 0;
              func = 0;
              waitInput = 0;
              break;
            default:
              msg[msgCtr] = val;
              putChar(msg[msgCtr]);
              msgCtr++;
              break;
          } // end nested switch of case func=5
          break;
    } // end switch
}//end logicFSM
